﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using Engine.Dtd.Schema;
using Engine.Sgml.Configuration;

namespace Engine.Sgml.Validation.Rules {
    [DebuggerNonUserCode]
    internal sealed class ValidationRuleCollection : ICollection<IValidationRule>, IEnumerable<IValidationRule> {
        internal static IValidationRule EmptyRule = new EmptyRule();
        private Dictionary<SName, IValidationRule> rules;
        private Dictionary<DName, IValidationRule> names;
        private DNameCollection nameCollection;

        public ValidationRuleCollection(DNameCollection nameCollection) {
            Guard.ArgumentNotNull(nameCollection, "nameCollection");
            this.nameCollection = nameCollection;
            this.rules = new Dictionary<SName, IValidationRule>(3);
            this.names = new Dictionary<DName, IValidationRule>(3);
            }

        internal void Initialize(DtdSchema schema, ValidatorBehavior behavior) {
            Debug.Assert(schema != null);
            Debug.Assert(behavior != null);

            nameCollection = schema.Names;
            Clear();
            Add(new DefaultRule(behavior));
            Add(new RootRule(SName.Get(schema.Name), behavior));
            DName name = nameCollection["table", false];
            if (name != null) {
                Add(new TableRule(SName.Get(name), behavior));
                //DElementDeclaration declaration = document.Schema.GetElementDeclaration(name);
                //foreach (IModelGroupsItem group in declaration.ContentModel.Groups) {
                //    if (group.Declaration.ContentModel.ContentType != DContentModelType.Empty)
                //        Add(new SurroundRule(SName.Get(group.Name), settings));
                //    }
                }
            }

        /// <summary>
        /// Adds a rule to the collection.
        /// </summary>
        /// <param name="item">A validation rule to add.</param>
        /// <exception cref="System.ArgumentNullException">If the item is null.</exception>
        public void Add(IValidationRule item) {
            Guard.ArgumentNotNull(item, "item");
            rules[item.Name] = item;
            if (item.Name == SName.Empty)
                return;
            DName name = nameCollection[item.Name.LocalName, false];
            if (name != null && !names.ContainsKey(name))
                names.Add(name, item);
            }

        /// <summary>
        /// Gets the rule for the specified element.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public IValidationRule this[SElement element] {
            get {
                Debug.Assert(element != null, "Could not get the rule for null.");
                IValidationRule rule;
                if (element.Name != null && rules.TryGetValue(element.Name, out rule))
                    return rule;
                if (element.DName != null && names.TryGetValue(element.DName, out rule))
                    return rule;
                return rules[SName.Empty];
                }
            }

        /// <summary>
        /// Removes all items from the collection.
        /// </summary>
        public void Clear() {
            names.Clear();
            rules.Clear();
            }

        /// <summary>
        /// Determines whether the collection contains a specific rule.
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public bool Contains(IValidationRule item) {
            if (item == null)
                return false;
            return rules.ContainsKey(item.Name);
            }

        /// <summary>
        /// Copies the elements of the collection to an
        /// array, starting at a particular array index.
        /// </summary>
        /// <param name="array"></param>
        /// <param name="arrayIndex"></param>
        /// <exception cref="System.NotSupportedException"></exception>
        public void CopyTo(IValidationRule[] array, int arrayIndex) {
            throw new NotSupportedException();
            }

        /// <summary>
        /// Gets the number of rules contained in the collection.
        /// </summary>
        public int Count {
            get { return rules.Count; }
            }

        /// <summary>
        /// Gets a value indicating whether the collection is read-only.
        /// This property always return false.
        /// </summary>
        public bool IsReadOnly {
            get { return false; }
            }

        /// <summary>
        /// Removes the first occurrence of a specific rule from the collection.
        /// </summary>
        /// <param name="item">A validation rule to remove.</param>
        /// <returns></returns>
        public bool Remove(IValidationRule item) {
            if (item == null)
                return false;
            return Remove(item.Name);
            }


        /// <summary>
        /// Removes the rule with the specified name from this collection.
        /// </summary>
        /// <param name="name">A name of validation rule.</param>
        /// <returns>true if a rule is successfully found and removed; otherwise, false.</returns>
        public bool Remove(SName name) {
            if (name == null)
                return false;
            DName dname = nameCollection[name.LocalName, false];
            if (dname != null)
                names.Remove(dname);
            return rules.Remove(name);
            }

        public IEnumerator<IValidationRule> GetEnumerator() {
            return rules.Values.GetEnumerator();
            }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
            return rules.GetEnumerator();
            }
        }
    }
